[코담]
웹개발·실전 프로젝트·AI까지, 파이썬·장고의 모든것을 담아낸 강의와 개발 노트
정규화 | ✅저자: 이유정(박사)
🔹 정규화란? 데이터를 중복 없이 정리하고, 나중에 에러 없이 쉽게 관리할 수 있게 테이블 구조를 만드는 규칙입니다.
❓ 왜 필요할까요?
- 데이터를 중복으로 쓰면 저장 공간 낭비.
- 하나만 바꾸면 되는 정보를 여러 군데 바꿔야 해서 오류 발생 가능성 높음.
- 테이블이 너무 복잡하거나 너무 커지는 걸 방지.
🔹 혼합된 비정규형 테이블
학생ID | 학생이름 | 반이름 | 반선생님 | 연락처 | 과목명 | 점수 |
---|---|---|---|---|---|---|
1 | 철수 | 1반 | 김선생님 | 010-1111-1111, 010-2222-2222 | 수학 | 90 |
1 | 철수 | 1반 | 김선생님 | 010-1111-1111, 010-2222-2222 | 영어 | 85 |
2 | 영희 | 1반 | 김선생님 | 010-3333-3333 | 수학 | 95 |
3 | 민수 | 2반 | 박선생님 | 010-4444-4444 | 영어 | 88 |
◽ 제1정규형 (1NF) – 원자값(더 이상 나눌 수 없는 값)만 허용
📖 규칙:
- 각 칸(컬럼)은 하나의 값만 가져야 합니다.
- 즉, 한 셀에 두 개 이상의 정보가 있으면 안됩니다.
학생ID | 학생이름 | 반이름 | 반선생님 | 연락처 | 과목명 | 점수 |
---|---|---|---|---|---|---|
1 | 철수 | 1반 | 김선생님 | 010-1111-1111 | 수학 | 90 |
1 | 철수 | 1반 | 김선생님 | 010-2222-2222 | 수학 | 90 |
1 | 철수 | 1반 | 김선생님 | 010-1111-1111 | 영어 | 85 |
1 | 철수 | 1반 | 김선생님 | 010-2222-2222 | 영어 | 85 |
2 | 영희 | 1반 | 김선생님 | 010-3333-3333 | 수학 | 95 |
3 | 민수 | 2반 | 박선생님 | 010-4444-4444 | 영어 | 88 |
✅ 연락처 한 셀에 하나만 넣었어요 → 원자값만 존재 → 1NF 완료 |
◽ 제2정규형 (2NF) – 부분 종속 제거 (복합키의 일부에만 의존하는 속성 분리)
📖 규칙:
- 기본키는
(학생ID + 과목명)
- 그런데
학생이름
,반이름
,반선생님
,연락처
는 과목 없이도학생ID
만 알면 됩니다.
📄 학생 테이블 (학생 정보만)
학생ID | 학생이름 | 반이름 | 연락처 |
---|---|---|---|
1 | 철수 | 1반 | 010-1111-1111 |
1 | 철수 | 1반 | 010-2222-2222 |
2 | 영희 | 1반 | 010-3333-3333 |
3 | 민수 | 2반 | 010-4444-4444 |
📄 성적 테이블 (학생ID + 과목명 기준)
학생ID | 과목명 | 점수 |
---|---|---|
1 | 수학 | 90 |
1 | 영어 | 85 |
2 | 수학 | 95 |
3 | 영어 | 88 |
✅ 과목 관련 정보만 남기고 나머지 정보는 학생 테이블로 이동 | ||
→ 부분 종속 제거 → 2NF 완료 |
- 이 표의 기본키는
(학생ID, 과목)
이에요. 왜냐하면 같은 학생이 여러 과목을 들으니까요. - 그런데
학생이름
은과목
이랑은 아무 상관이 없잖아요? “학생 이름은 과목에 따라 바뀌는 것도 아닌데 같이 있을 필요가 없습니다. 그래서 학생의 이름은 학생ID랑만 연결합니다.
💡 핵심 규칙: 복합키일 때, 그 일부에만 의존하는 정보는 따로 떼어내기!
◽ 제3정규형 (3NF) – 이행 종속 제거
📖 규칙:
반이름
→반선생님
이므로,반선생님
은 중간 컬럼(반이름)을 거쳐야만 알 수 있습니다. 그래서 분리해야 합니다.- 반 정보를 따로 빼서
반이름
과반선생님
을 연결!
📄 반 테이블
반이름 | 반선생님 |
---|---|
1반 | 김선생님 |
2반 | 박선생님 |
✅ 이제 모든 테이블이 역할별로 완전히 정리되었습니다. | |
→ 3NF까지 완료! |
✅ 최종 정규화 완료: 4개의 테이블로 나눠짐
학생ID | 학생이름 | 반이름 |
---|---|---|
1 | 철수 | 1반 |
2 | 영희 | 1반 |
3 | 민수 | 2반 |
학생 테이블: 학생의 고유 정보 (ID, 이름, 반) |
학생ID | 연락처 |
---|---|
1 | 010-1111-1111 |
1 | 010-2222-2222 |
2 | 010-3333-3333 |
3 | 010-4444-4444 |
연락처 테이블: 학생 1명이 여러 연락처를 가질 수 있으므로 분리 (1:N 관계) |
학생ID | 과목명 | 점수 |
---|---|---|
1 | 수학 | 90 |
1 | 영어 | 85 |
2 | 수학 | 95 |
3 | 영어 | 88 |
성적 테이블: 복합키 (학생ID, 과목명) 기반으로 성적 저장 |
반이름 | 반선생님 |
---|---|
1반 | 김선생님 |
2반 | 박선생님 |
반 테이블: 반이름을 기준으로 반선생님을 구분 |
✅ 관계 요약 (ERD 개념)
학생ID
→연락처
,성적
,학생 테이블
과 연결됨반이름
→학생
,반 테이블
과 연결됨
📖 정규화 정리
정규화 단계 | 규칙 설명 | 쉽게 말하면… |
---|---|---|
1NF (제1정규형) | 원자값만 허용 | 셀마다 값 하나만 써야 해요. |
2NF (제2정규형) | 부분 종속 제거 | 복합키의 일부에만 의존하는 컬럼은 빼요. |
3NF (제3정규형) ...... | 이행 종속 제거 ..... | 기본키를 거치지 않고 다른 컬럼을 통해서만 알 수 있는 정보는 분리해요. |
Student
: 학생 기본 정보 (student_id
,name
,classroom
)Phone
: 연락처 (1명의 학생이 여러 연락처 가능)Score
: 성적 정보 (student
,subject
,score
)Classroom
: 반 정보 (class_name
,teacher
)
Django 모델
# models.py
from django.db import models
# 1. 반 정보 테이블
class Classroom(models.Model):
class_name = models.CharField(max_length=10, unique=True) # 예: '1반', '2반'
teacher = models.CharField(max_length=50) # 예: '김선생님'
def __str__(self):
return f"{self.class_name} ({self.teacher})"
# 2. 학생 테이블
class Student(models.Model):
name = models.CharField(max_length=50)
classroom = models.ForeignKey(Classroom, on_delete=models.CASCADE, related_name='students')
def __str__(self):
return f"{self.name} - {self.classroom.class_name}"
# 3. 연락처 테이블
class Phone(models.Model):
student = models.ForeignKey(Student, on_delete=models.CASCADE, related_name='phones')
number = models.CharField(max_length=20)
def __str__(self):
return f"{self.student.name}: {self.number}"
# 4. 성적 테이블
class Score(models.Model):
student = models.ForeignKey(Student, on_delete=models.CASCADE, related_name='scores')
subject = models.CharField(max_length=30)
score = models.PositiveIntegerField()
class Meta:
unique_together = ('student', 'subject') # 복합키 대체
def __str__(self):
return f"{self.student.name} - {self.subject}: {self.score}"
Classroom
: 반이름(class_name)과 반선생님(teacher)을 저장
Student
: 학생이름(name)과 소속 반(classroom)을 연결
Phone
: 학생의 연락처 — 학생당 여러 개 가능 (1:N)
Score
: 학생과 과목, 점수를 저장 — 학생ID + 과목이 고유 (복합키 역할)